package com.sohoometer.assignmeter.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.nari.coreframe.service.GenericServiceImpl;
import com.nari.heatshare.dao.IAssignMeterDao;
import com.nari.heatshare.dao.IAssignMeterDataGatherDao;
import com.nari.heatshare.model.IAssignMeterDataGather;
import com.sohoometer.assignmeter.bean.AssignMeterDataExceptionQuery;
import com.sohoometer.assignmeter.bean.AssignMeterDataExceptionResult;
import com.sohoometer.assignmeter.bean.ExceptionType;
import com.sohoometer.assignmeter.dao.AssignMeterDataExceptionQueryDao;
import com.sohoometer.assignmeter.dao.AssignMeterDataExceptionResultDao;

@Service("assignMeterDataExceptionQueryService")
public class AssignMeterDataExceptionQueryServiceImpl extends
		GenericServiceImpl<AssignMeterDataExceptionQuery, String> implements
		AssignMeterDataExceptionQueryService {
	@Autowired
	private	ThreadPoolTaskExecutor threadPoolTaskExecutor = null;
	@Autowired
	private  AssignMeterDataExceptionResultDao assignMeterDataExceptionResultDao= null;
	@Autowired
	private AssignMeterDataExceptionQueryDao assignMeterDataExceptionQueryDao = null;
	@Autowired
	private IAssignMeterDao iAssignMeterDao = null;
	@Autowired
	private IAssignMeterDataGatherDao iAssignMeterDataGatherDao = null;
	@Autowired
	private DataSourceTransactionManager dataSourceTxManager = null;
	@Autowired
	private  HibernateTransactionManager hibernateTxManager = null;
	public AssignMeterDataExceptionQueryServiceImpl() {
	}
	@Autowired
	public AssignMeterDataExceptionQueryServiceImpl(
			AssignMeterDataExceptionQueryDao assignMeterDataExceptionQueryDao) {
		setiGenericDao(assignMeterDataExceptionQueryDao);
		this.assignMeterDataExceptionQueryDao = assignMeterDataExceptionQueryDao;
	}
	/**
	 * 根据用户的查询条件对分配表数据进行查询 处理以下情况 1.分配表当天未上传,查出分配表最后一次上传时间 2.分配表读书异常
	 * 3.分配表前后板温度异常 4.热阻塞异常 5.分配表电池以及被拆问题
	 * */
	/**
	 * 代码逻辑: 1.先根据查询条件查询所需要核实的分配表号列表 2.将日期从起始日期到结束日期依次轮询进行检查
	 * 3.将这条数据进行规则匹配并将相应的数据进行标记,采用int 4字节 32位状态的数值进行状态标识 4.将查询数据的ID以及附属信息保存到数据库中
	 * 
	 * */
	@Override
	public void  dealWithQuery(final AssignMeterDataExceptionQuery query,final String id) {
		//处理档案中的分配表 得到分配表基本信息
		//是否有自定义异常
		Runnable  task = new Runnable() {
			@Override
			public void run() {
				//运行前开启事务,在运行后关闭事务
				DefaultTransactionDefinition  def = new DefaultTransactionDefinition();
				def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
				TransactionStatus transaction = hibernateTxManager.getTransaction(def);
//				DefaultTransactionDefinition  def2 = new DefaultTransactionDefinition();  //取消JDBC事务提交
//				def2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
//				TransactionStatus transaction2 = dataSourceTxManager.getTransaction(def2);
				dealWithUnUpload(query,id);
				try {
					dealWithDataException(query,id);
				} catch (Exception e) {
					e.printStackTrace();
				}
				uploadState(id);
				//提交事务
				hibernateTxManager.commit(transaction);
//				dataSourceTxManager.commit(transaction2);
			}
		};
		threadPoolTaskExecutor.execute(task, AsyncTaskExecutor.TIMEOUT_IMMEDIATE); //马上执行,看出执行时间
//		Thread thread = new Thread(task); // 使用线程池来做
//		Random random = new Random();
//		int nextInt = random.nextInt(2000000);
//		thread.setName("AssignMeterExceptionData-Pick"+nextInt);
//		thread.start();
	}
/**
 * 处理异常数据问题
 * 迭代在查询期间中每天的数据,筛选数据后将不符合的数据进行保存然后显示
 * @throws Exception 
 * 
 * */
	private void dealWithDataException(AssignMeterDataExceptionQuery query,
			String id) throws Exception {
		ArrayList<String> seriousNo = getSeriousNo(query);
		for(String serious : seriousNo) {
			List<IAssignMeterDataGather> queryAssignMeterData = iAssignMeterDataGatherDao.queryAssignMeterData(serious, query.getStartRecordTime(), query.getEndRecordTime());
			dealWithSingleData(serious,queryAssignMeterData,query,id);
		}
	}
/**
 * 	处理单条数据 如果数据有异常,则新建数据结果,将结果显示出来 
 * @param query 
 * */
private void dealWithSingleData(String serious,List<IAssignMeterDataGather> queryAssignMeterData, AssignMeterDataExceptionQuery query, String id) {
	if(queryAssignMeterData==null||queryAssignMeterData.size()<1) return;
	//遍历数据,将数据分别按照异常种类进行数据筛选
	for(IAssignMeterDataGather assignMeterDataGather : queryAssignMeterData) {
				//对数据进行处理 分别处理
				//热阻塞
		if(query.getHeatBlock()!=null&&query.getHeatBlock()) {
			dealWithHeatBlock(assignMeterDataGather,id);
		}
		//温度异常
		if(query.getTempException()!=null&&query.getTempException()){
			dealWithTempException(assignMeterDataGather,id);
		}
		dealWtihSelfDefine(assignMeterDataGather,query,id);
				//对特殊值进行约束的异常
	}
}
/**
 * 处理自定义异常
 * 根据用户所定条件进行筛选,且所选条件之间是且的关系
 * */
	private void dealWtihSelfDefine(IAssignMeterDataGather assignMeterDataGather,
		AssignMeterDataExceptionQuery query, String id) {
		boolean met = false;
		int exceptionType = 0;
		double fontTemperature = assignMeterDataGather.getFontTemperature();
		double backTmperature = assignMeterDataGather.getBackTmperature();
		double tempDiff = new BigDecimal(fontTemperature).subtract(new BigDecimal(backTmperature)).abs().doubleValue();
		//读数是否满足
		//默认情况下不验证,如果条件满足则进行验证
		boolean readMet = true;
		Double queryreadNum = query.getReadNum();
		double readNum = assignMeterDataGather.getReadNum();
		if(queryreadNum!=null&&queryreadNum!=0) {
			readMet = ifMet(query.getReadNumCom(), queryreadNum, readNum);
			if(readMet) exceptionType+=ExceptionType.READNUM_EXCEPTION;
		}
		//前板温度
		Double queryfontTemperature = query.getFontTemperature();
		boolean fontTempMet = true;
		if(queryfontTemperature!=null&&queryfontTemperature!=0) {
			fontTempMet = ifMet(query.getFontTemperatureCom(), queryfontTemperature, fontTemperature);
			if(fontTempMet) exceptionType+=ExceptionType.FONTTEMP_EXCEPTION;
		}
		//后板温度
		Double querybackTmperature = query.getBackTmperature();
		boolean backTempMet = true;
		if(querybackTmperature!=null&&querybackTmperature!=0) {
			backTempMet = ifMet(query.getBackTmperatureCom(), querybackTmperature, backTmperature);
			if(backTempMet) exceptionType+=ExceptionType.BACKTEMP_EXCEPTION;
		}
		//温差
		Double queryTemperatureDiff = query.getTemperatureDiff();
		boolean tempDiffMet = true;
		if(queryTemperatureDiff!=null&&queryTemperatureDiff!=0) {
			tempDiffMet = ifMet(query.getTemperatureDiffCom(), queryTemperatureDiff, tempDiff);
			if(tempDiffMet) 
			{
				exceptionType+=ExceptionType.TEMPDIFF_EXCEPTION;
				}
		}
		met=readMet&fontTempMet&backTempMet&tempDiffMet;
		if(met&&exceptionType>0) {
			exceptionType+=ExceptionType.SELF_EXCEPTION;
			AssignMeterDataExceptionResult result = getResult(assignMeterDataGather, id, exceptionType);
			saveResult(result);
		}
}

	
private boolean ifMet(String queryCom, Double queryreadNum,
		double readNum) {
	boolean flag = false;
	String readNumCom = queryCom;
	if("s".equals(readNumCom)) {
		flag = readNum<queryreadNum;
	}
	if("b".equals(readNumCom)) {
		flag = readNum>queryreadNum;
	}
	return flag;
}
	/**
	 * 处理温度异常
	 * */
	private void dealWithTempException(
		IAssignMeterDataGather assignMeterDataGather, String id) {
		double fontTemperature = assignMeterDataGather.getFontTemperature();
		double backTmperature = assignMeterDataGather.getBackTmperature();
		double substract = new BigDecimal(fontTemperature).subtract(new BigDecimal(backTmperature)).doubleValue();
//		double tempDiff = new BigDecimal(fontTemperature).subtract(new BigDecimal(backTmperature)).abs().doubleValue(); //前后板温差
		 //前板温度比背板温度大于3度或者任何温度大于60度
		if(substract>=3|fontTemperature>=60|backTmperature>=60) {
			AssignMeterDataExceptionResult result = getResult(assignMeterDataGather, id, ExceptionType.TEMP_EXCEPTION);
			saveResult(result);
		}
}
	/**
	 * 处理热阻塞异常
	 * 
	 * 前后板温度均大于35度 且温差小于1度
	 * */
	private void dealWithHeatBlock(IAssignMeterDataGather assignMeterDataGather,
		String id) {
		double fontTemperature = assignMeterDataGather.getFontTemperature();
		double backTmperature = assignMeterDataGather.getBackTmperature();
		double tempDiff = new BigDecimal(fontTemperature).subtract(new BigDecimal(backTmperature)).abs().doubleValue();
		if(fontTemperature>35&&backTmperature>35&tempDiff<=1) {
			//发生热阻塞
			AssignMeterDataExceptionResult result = getResult(assignMeterDataGather, id,ExceptionType.HEAT_BLOCK);
			saveResult(result);
		}
}
	/**
	 *   保存查询结果
	 * */
	private void saveResult(AssignMeterDataExceptionResult result) {
		try {
			assignMeterDataExceptionResultDao.saveEntity(result);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private AssignMeterDataExceptionResult getResult(IAssignMeterDataGather assignMeterDataGather,
			String id, int exceptionType) {
		AssignMeterDataExceptionResult result  = new AssignMeterDataExceptionResult();
		result.setQueryid(id);
		result.setDataid(assignMeterDataGather.getId());
		result.setExceptionType(exceptionType);
		result.setReadTime(assignMeterDataGather.getReadTime());
		result.setFontTemperature(assignMeterDataGather.getFontTemperature());
		result.setBackTmperature(assignMeterDataGather.getBackTmperature());
		result.setSeriousNum(assignMeterDataGather.getSeriousNum());
		result.setReadNum(assignMeterDataGather.getReadNum());
		return result;
	}
	/*
 * 未上传: 在查询时间内 分配表的最后一次上传时间小于查询结束时间属于未上传
 * 先查询分配表在结束日期前一段时间内(距endDate一段时间内)的上传情况，如果没有上传则查询最后一次上传时间
 * 如果最后一次上传时间大于查询日期的结束日期,则认为该分配表上传了数据,否则认为不上传
 * */
	private void dealWithUnUpload(AssignMeterDataExceptionQuery query, String id) {
			//先加载所有档案上所有的分配表号
		ArrayList<String> seriousNos = getSeriousNo(query);
		if(seriousNos==null|| seriousNos.size()<1) return;
		Date endTime = query.getEndRecordTime();
		int day = query.getEndDay();
		if(day<0) return;
		Calendar instance = Calendar.getInstance();
		instance.setTime(endTime);
		instance.roll(Calendar.DAY_OF_YEAR,-day);//回滚相应的天数
		Date startTime = instance.getTime();
		for(String seriousNo : seriousNos) {
			try {
				List<IAssignMeterDataGather> queryAssignMeterData = iAssignMeterDataGatherDao.queryAssignMeterDataWithLimit(seriousNo, startTime, endTime, 1);
				if(queryAssignMeterData!=null&&queryAssignMeterData.size()>0) { continue;}//在某一时间上传过
				Date lastUploadDate = iAssignMeterDataGatherDao.queryLastUploadDate(seriousNo);
				if(lastUploadDate!=null) {
					if(lastUploadDate.after(endTime)) continue;
				}
				//此时说明该数据不符合要求 记录最后一次上传时间
				AssignMeterDataExceptionResult result = new AssignMeterDataExceptionResult();
				result.setSeriousNum(seriousNo);//设置分配表号
				result.setQueryid(query.getId());
				result.setExceptionType(ExceptionType.NOT_UPLOAD);
				result.setReadTime(lastUploadDate);
				saveResult(result);
			} catch (Exception e) {
				continue;
			}
		}
	}
	private ArrayList<String> getSeriousNo(AssignMeterDataExceptionQuery query) {
		ArrayList<String> queryAssignMeterNo = null;
		try {
			queryAssignMeterNo = iAssignMeterDao.queryAssignMeterNo(null, query.getProjectID(), query.getCommunityID(), query.getBuildingID(), null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return queryAssignMeterNo;
	}
	private void uploadState(String id) {
		try {
			AssignMeterDataExceptionQuery queryEntityById = assignMeterDataExceptionQueryDao.queryEntityById(id);
			queryEntityById.setIsdone(Boolean.TRUE);
			assignMeterDataExceptionQueryDao.saveOrUpdateEntity(queryEntityById);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private boolean checkSelfException(AssignMeterDataExceptionQuery query) {
		Double backTmperature = query.getBackTmperature();
		if (backTmperature != null && !backTmperature.equals(0)) {
			return true;
		}
		Double readNum = query.getReadNum();
		if (readNum != null && !readNum.equals(0)) {
			return true;
		}
		Double fontTemperature = query.getFontTemperature();
		if (fontTemperature != null && !fontTemperature.equals(0)) {
			return true;
		}
		Double temperatureDiff = query.getTemperatureDiff();
		if (temperatureDiff != null && !temperatureDiff.equals(0)) {
			return true;
		}
		return false;
	}

	/*
	 * 由于在添加Query时事务的不同步 造成事务提交错误
	 * **/
	@Deprecated 
	@Override
	public void addQuery(AssignMeterDataExceptionQuery query) throws Exception {
		String id = assignMeterDataExceptionQueryDao.saveEntity(query);
		dealWithQuery(query, id);
	}
	

	@Override
	public void deleteQuery(String id) throws Exception {
		assignMeterDataExceptionQueryDao.deleteEntityById(id);
		assignMeterDataExceptionResultDao.deleteResultByQueryId(id);
	}

}
